# ExecutableProjection.java

    package org.codefilarete.stalactite.engine;

    import java.util.Set;
    import java.util.function.Consumer;
    import java.util.function.Function;

    import org.codefilarete.stalactite.engine.EntityCriteria.CriteriaPath;
    import org.codefilarete.stalactite.query.model.Select;
    import org.codefilarete.stalactite.query.model.Selectable;
    import org.codefilarete.stalactite.sql.result.Accumulator;

    /**
     * Little interface to declare a projection as executable.
     *
     * @see PersistenceContext.ExecutableBeanPropertyKeyQueryMapper
     * @see EntityPersister.ExecutableEntityQuery
     */
    public interface ExecutableProjection {

    	/**
    	 * Adds a select inspector to this projection.
    	 * Made to collect information about the selectable available in the select clause.
    	 * The given consumer is not supposed to modify the select clause in here because the {@link ExecutableProjection} has been built earlier with
    	 * a select clause adapter. Thus making it again is useless. As a consequence, any modification to the provided {@link Select} has non effect
    	 * on the final select clause.
    	 *
    	 * @param select the select clause adapter that will get a copy of the final Select clause
    	 */
    	void selectInspector(Consumer<Set<Selectable<?>>> select);

    	/**
    	 * Marks this projection to apply the <code>distinct</code> SQL keyword
    	 * @return the current instance to chain with other methods
    	 */
    	ExecutableProjection distinct();

    	/**
    	 * Will run an underlying projection and executes given {@link Accumulator} on its result.
    	 *
    	 * @param accumulator projection result finalizer, {@link java.sql.ResultSet} values are read through the given {@link Function}
    	 * @return beans found by the query and finalized by accumulator
    	 * @param <R> result type
    	 */
    	<R> R execute(Accumulator<? super ProjectionDataProvider, ?, R> accumulator);

    	interface ProjectionDataProvider {

    		/**
    		 * Get a column value from its alias.
    		 * Made for cases of projected value like {@code count} operator to easily retrieve the value by its alias
    		 * instead of sharing the {@link org.codefilarete.stalactite.query.model.operator.Count} instance which is cumbersome.
    		 *
    		 * @param alias the column alias to retrieve data for
    		 * @param columnType the expected data type
    		 * @return the column value in the result set
    		 * @param <O> data type
    		 */
    		default <O> O getValue(String alias, Class<O> columnType) {
    			return getValue(new Selectable.SimpleSelectable<>(alias, columnType));
    		}

    		<O> O getValue(Selectable<O> selectable);

    		<O> O getValue(CriteriaPath<?, O> selectable);
    	}
    }